function [result_image] = dithering_ordered(original_image, result_bits, matrix_size)
% DITHERING

% Algoritmo ordered
% - Metodo per ridurre il numero di bit di intensita' di un'immagine
%   applicando una matrice di sogliatura pseudo-random sull'errore
%   di quantizzazione dei pixel

% Profondita' in bit dell'immagine originale
original_bits = 8;
original_levels = 2^original_bits-1;

% Setto il numero di bit dell'immagine in uscita (< di quello in entrata)
result_levels = 2^result_bits-1;

% Creo il frame dell'immagine risultante
result_image = zeros(size(original_image, 1),...
    size(original_image, 2),...
    size(original_image, 3));

% Creazione della matrice di sogliatura errore
threshold_matrix = (1/matrix_size^2) * magic(matrix_size) * result_levels;

% ALGORITMO
% per ogni canale colore
for c = 1:size(original_image, 3)

    % per ogni y (da sopra a sotto)
    for y = 2:size(result_image, 1)-1

        % per ogni x (da sinistra a destra)
        for x = 2:size(result_image, 2)-1

            % prendo il pixel originale
            old_pixel = original_image(y,x,c);

            % quantizzo il pixel
            new_pixel = double(old_pixel) *...
                (result_levels/original_levels);
            
            % calcolo le coordinate cicliche per la matrice
            i = mod(x, matrix_size)+1;
            j = mod(y, matrix_size)+1;
            
            % quantizzo il pixel tramite la matrice
            if(new_pixel > threshold_matrix(j,i))
                new_pixel = ceil(double(old_pixel) *...
                    (result_levels/original_levels));
            else
                new_pixel = floor(double(old_pixel) *...
                    (result_levels/original_levels));
            end

            % salvo il risultato finale
            result_image(y,x,c) =...
                new_pixel * (original_levels/result_levels);
        end
    end
end

end